package com.rc.common.advice;

import cn.dev33.satoken.stp.StpUtil;
import com.mybatisflex.core.tenant.TenantManager;
import com.rc.common.util.JsonUtil;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.UUID;

/**
 * 对接口日志进行追踪
 */
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class ApiAdvice {
    @Around("@annotation(com.rc.common.annotate.ApiLog)")
    public Object apiOperationLogAround(ProceedingJoinPoint point) throws Throwable {
        try {
            //请求跟踪 底部使用ThreadLocal
            MDC.put("traceId", UUID.randomUUID().toString());

            var start = System.currentTimeMillis();

            var className = point.getTarget().getClass().getSimpleName();
            var signature = (MethodSignature) point.getSignature();
            var methodName = signature.getName();

            var apiOperationAnnotation = signature.getMethod().getAnnotation(ApiOperation.class);
            var apiOperation = Objects.isNull(apiOperationAnnotation) ? "":apiOperationAnnotation.value();

            var args = point.getArgs();
            log.info("请求开始:[{}-{}], 当前用户角色: {},入参: {}, 请求方法: {}",
                    className, apiOperation, StpUtil.getRoleList(), JsonUtil.toJson(args), methodName);

            var result = point.proceed();

            var executionTime = System.currentTimeMillis() - start;

            log.info("请求结束:[{}], 耗时: {}ms, 出参: {} ", apiOperation, executionTime, JsonUtil.toJson(result));
            return result;
        } finally {
            //避免污染其他请求
            MDC.clear();
        }
    }


    @Around("@annotation(com.rc.common.annotate.WithoutTenant)")
    public Object query(ProceedingJoinPoint point) throws Throwable {
        try {
            TenantManager.ignoreTenantCondition();

            //此处操作的数据不会带有 tenant_id 的条件

            return point.proceed();
        } finally {
            TenantManager.restoreTenantCondition();
        }
    }
}
